/**
 * 公式计算
 * 使用实例：
 * --------------
 * # common JS
 * const wecal = require('lib/weCal/weCal.js')
 * # es6
 * import wecal from 'lib/weCal/weCal.js'
 * let str = '-(-5+(-2*33/3*4)-2)+((5*6)/2+2)-23*4/2+43'
 * let value = wecal.dealBracket(str)
 */

class WeCal {
  constructor() {
    this.signArr = ['+', '-', '*', '/'];
    this.suitArr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'];
  }

  // 去除多余的符号:取最后一个
  dealNeedlessSign(str, type) {
    let _str = str;

    // 去除首尾括号
    if (type === 1) {
      _str = _str.slice(1, str.length - 1);
    }
    const _arr = this.cutStr(_str);

    // 计算运算和
    const resultVal = this.simpleOperation(_arr);
    return resultVal;
  }

  // 处理多重括号:类比入栈和出栈操作：以一对()为最小执行单位
  dealBracket(str) {
    // 在执行操作前去除多余的符号
    let _str = this.dropSign(str);

    // 判断解括号次数,防止死循环
    const bracketLength = _str.split(')').length - 1;
    for (let i = 0; i < bracketLength; i++) {
      const rightBracketIdx = _str.indexOf(')');
      const strInclueBracket = _str.substr(0, rightBracketIdx + 1);
      const lastLeftBracketIdx = strInclueBracket.lastIndexOf('(');
      const fragment = _str.slice(lastLeftBracketIdx, rightBracketIdx + 1);
      _str =
        _str.slice(0, lastLeftBracketIdx) +
        this.dealNeedlessSign(fragment, 1) +
        _str.slice(rightBracketIdx + 1, _str.length);
    }
    const newArr = this.cutStr(_str);
    const value = this.simpleOperation(newArr);
    return value;
  }

  // 简单运算:字符串加减乘除
  simpleOperation(newArr) {
    let _newArr = newArr;
    while (_newArr.length >= 3) {
      // 先判断乘号分支;
      const mulSign = _newArr.indexOf('*') > 0;
      const diviSign = _newArr.indexOf('/') > 0;
      if (mulSign) {
        // 判断是否有除号:有则判断顺序执行,无则执行乘法
        if (diviSign) {
          if (mulSign < diviSign) {
            _newArr = this.doOperation(_newArr, '*');
          } else {
            _newArr = this.doOperation(_newArr, '/');
          }
        } else {
          _newArr = this.doOperation(_newArr, '*');
        }
        continue;
      }

      // 是否有除:有则执行
      if (diviSign) {
        _newArr = this.doOperation(_newArr, '/');
        continue;
      }

      // 然后判断加减分支
      const addSign = _newArr.indexOf('+') > 0;
      const subSign = _newArr.indexOf('-') > 0;
      if (!addSign) {
        // 是否有减:有则执行
        if (subSign) {
          _newArr = this.doOperation(_newArr, '-');
        }
        continue;
      }

      // 判断是否有加号:有则判断顺序执行,无则执行减法
      if (subSign) {
        if (addSign < subSign) {
          _newArr = this.doOperation(_newArr, '+');
        } else {
          _newArr = this.doOperation(_newArr, '-');
        }
      } else {
        _newArr = this.doOperation(_newArr, '+');
      }
    }
    return _newArr[0];
  }

  _getTempStr(_str, newArr, i) {
    let tempStr = '';
    if (this.signArr.indexOf(_str.charAt(i)) >= 0) {
      // 是符号且为减号
      if (_str.charAt(i) === '-') {
        if (tempStr.indexOf('-') < 0) {
          if (tempStr !== '') {
            newArr.push(tempStr);
          }
          tempStr = '-';
        } else {
          if (tempStr === '-') {
            tempStr = '';
          } else {
            newArr.push(tempStr);
            newArr.push(_str.charAt(i));
            tempStr = '';
          }
        }
      } else {
        if (tempStr !== '') {
          newArr.push(tempStr);
        }
        newArr.push(_str.charAt(i));
        tempStr = '';
      }
    } else {
      tempStr += _str.charAt(i);
    }
    return tempStr;
  }

  // 将字符串分割成数字和符号的数组
  cutStr(_str) {
    const newArr = [];
    let tempStr = '';
    for (let i = 0; i < _str.length; i++) {
      if (i === _str.length - 1) {
        tempStr += _str.charAt(i);
        newArr.push(tempStr);
      } else {
        tempStr = this._getTempStr(_str, newArr, i);
      }
    }

    // 最后将减号变负数留下的空隙补'+'
    const ixArr = [];
    for (let i = 0; i < newArr.length; i++) {
      if (!isNaN(Number(newArr[i - 1])) && !isNaN(Number(newArr[i]))) {
        ixArr.push(i);
      }
    }
    ixArr.reverse().forEach(item => {
      newArr.splice(item, 0, '+');
    });
    return newArr;
  }

  // 符号运算
  doOperation(arr, sign) {
    while (arr.indexOf(sign) > 0 && arr.indexOf(sign) < arr.length - 1) {
      const idx = arr.indexOf(sign);
      let joinVal = '';
      if (sign === '*') {
        joinVal = Number(arr[idx - 1]) * Number(arr[idx + 1]);
      }
      if (sign === '/') {
        joinVal = Number(arr[idx - 1]) / Number(arr[idx + 1]);
      }
      if (sign === '+') {
        joinVal = Number(arr[idx - 1]) + Number(arr[idx + 1]);
      }
      if (sign === '-') {
        joinVal = Number(arr[idx - 1]) - Number(arr[idx + 1]);
      }
      arr.splice(idx - 1, 3, joinVal);
    }
    return arr;
  }

  // 丢弃多余的符号
  dropSign(str) {
    const arr = str.split('');

    // 数组:符号对应下标
    const ixArr = [];

    // 数组:丢弃符号下标
    const lostArr = [];
    for (const idx in arr) {
      if (this.signArr.indexOf(arr[idx]) >= 0) {
        ixArr.push(Number(idx));
      }
    }
    if (ixArr.length > 1) {
      ixArr.reduce((x, y) => {
        if (Number(y) - Number(x) === 1) {
          lostArr.push(Number(x));
        }
        return y;
      });
    }
    lostArr.reverse().forEach(item => {
      arr.splice(item, 1);
    });
    return arr.reduce((x, y) => String(x) + y);
  }
}
const weCal = new WeCal();

export default weCal;
